home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 398 / 398.xpi / chrome / forecastfox.jar / content / profiles / migrator-service.js next >
Text File  |  2010-02-04  |  17KB  |  554 lines

  1. /*------------------------------------------------------------------------------
  2.   Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
  3.   ----------------------------------------------------------------------------*/
  4.  
  5. /******************************************************************************
  6.  * Retrieve the version attribute from a profile document.
  7.  * It first tries the documentElement then the children of the element.
  8.  *
  9.  * @param   The document to inspect.    
  10.  * @return  The version string or null if version can not be found.
  11.  *****************************************************************************/
  12. function getVersion(aDoc)
  13. {
  14.   //version found on the document element.
  15.   if (aDoc.documentElement.hasAttribute("version"))
  16.     return aDoc.documentElement.getAttribute("version");
  17.     
  18.   //loop through the child nodes looking for the version
  19.   var node = aDoc.documentElement.firstChild;
  20.   while (node) {
  21.       
  22.     //found the version attribute
  23.     if (node.nodeType != node.TEXT_NODE &&
  24.         node.hasAttribute("version"))
  25.       return node.getAttribute("version");
  26.     
  27.     //get the next node
  28.     node = node.nextSibling;
  29.   }
  30.     
  31.   //version not found
  32.   return null;
  33. }
  34.       
  35. /******************************************************************************
  36.  * Interface used for profile migration services.  Implements 
  37.  * version checking, importing, exporting, and migrating.
  38.  * 
  39.  * @status    FROZEN
  40.  * @version   1.0
  41.  *****************************************************************************/
  42. function MigratorService() 
  43. {
  44.   //setup a new error
  45.   this._error = Cc["@ensolis.com/forecastfox/error-item;1"].
  46.                 createInstance(Ci.ffIErrorItem);    
  47. }
  48. MigratorService.prototype = {
  49.   __proto__: new ServiceBase("MigratorService"),
  50.   _dskSvc: null,
  51.   _items: null,
  52.     
  53.   ///////////////////////////
  54.   // ffIService 
  55.  
  56.   /**
  57.    * Start the migrator service.  Called by the manager service.
  58.    */       
  59.   start: function MigratorService_start()
  60.   {                      
  61.     //setup disk service
  62.     var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
  63.                  getService(Ci.ffIManagerService);
  64.     this._dskSvc = mgrSvc.disk;
  65.     
  66.     //return success
  67.     return true;                                   
  68.   },
  69.   
  70.   /**
  71.    * Stop the migrator service.  Called by the manager service. 
  72.    */  
  73.   stop: function MigratorService_stop()
  74.   {
  75.     //clear variables
  76.     this._items = null;
  77.     this._dskSvc = null;
  78.   },
  79.     
  80.   ///////////////////////////
  81.   // ffIMigratorService 
  82.       
  83.   /**
  84.    * Compares 2 version strings.
  85.    * 
  86.    * @param   From version string.
  87.    * @param   To version string.
  88.    * @return  -1 if from less than to, 0 if the are the same and 1 if greater.
  89.    */  
  90.   compare: function MigratorService_compare(aFrom, aTo)
  91.   {
  92.     var checker = Cc["@mozilla.org/xpcom/version-comparator;1"].
  93.                   getService(Ci.nsIVersionComparator);  
  94.     return checker.compare(aFrom, aTo);
  95.   },
  96.   
  97.   /**
  98.    * Migrate the profile service to the current version.
  99.    *
  100.    * @param   The profile service.
  101.    * @return  False if migration fails.  Use the lastError property
  102.    *          for more information on the failure.
  103.    */
  104.   migrate: function MigratorService_migrate(aService) 
  105.   {
  106.     //setup error variables
  107.     const PREFIX = "ff.migrator.migrate.";
  108.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  109.     var message = "";
  110.  
  111.     if (!getPref("onetime.chromepromo")) {
  112.       setPref("onetime.chromepromo", true, true);
  113.       openLink("http://blog.getforecastfox.com/2010/02/forecastfox-weather-for-google-chrome.html", "tab");
  114.     }
  115.     
  116.     //determine if we need to migrate
  117.     var branch = getBranch(false, null);
  118.     var previous = branch.prefHasUserValue("migrated");
  119.     
  120.     //previous version not installed so do nothing
  121.     if (!previous) {
  122.       setPref("migrated", "0.9.10"); 
  123.       return true;
  124.     }
  125.       
  126.     //complete the uninstallation/upgrade of weatherfox
  127.     var from = getPref("migrated");
  128.     if (from == "*") {
  129.       branch = getBranch(false, "weatherfox.");
  130.       branch.deleteBranch("");
  131.       var file = this._dskSvc.get("", TYPE_WEATHERFOX);
  132.       try {
  133.         removeFile(file);
  134.       } catch(e) {}
  135.     }
  136.           
  137.     //load the profiles document
  138.     var doc = this._loadDoc(aService);
  139.     
  140.     //document not loaded
  141.     var err;
  142.     if (!doc) {
  143.       err = this.lastError;
  144.       this._error.init(err.severity, name, err.message);
  145.       return false;
  146.     }
  147.        
  148.     //return an error if no profiles in the document
  149.     var profiles = doc.getElementsByTagName("profile");
  150.     if (profiles.length == 0) {
  151.       message = this.bundle.GetStringFromName(PREFIX + "profiles.message");
  152.       this._error.init(SEVERITY_ERROR, name, message);
  153.       return false;
  154.     }
  155.  
  156.     //get the from version
  157.     var version = getVersion(doc);
  158.     if (version == null)
  159.       version = from;
  160.     
  161.     //coming from weatherfox and can not determine version so we are finished
  162.     if (version == "*") {
  163.       setPref("migrated", "0.9.10"); 
  164.       return true;
  165.     }
  166.       
  167.     //loop through the nodes and create profile items
  168.     this._items = {};
  169.     for (var i=0; i<profiles.length; i++) {
  170.       var item = aService.createItem(profiles[i]);
  171.       this._items[item.ID] = item.clone();
  172.     }
  173.     
  174.     //run the upgrade if needed
  175.     var success = this._upgrade(version);
  176.     
  177.     //return an error if the upgrade failed
  178.     if (!success) {
  179.       err = this.lastError;
  180.       this._error.init(err.severity, name, err.message);
  181.       return false;
  182.     }
  183.     
  184.     //remove any old profiles
  185.     var items = aService.getItems({});
  186.     for (i=0; i<items.length; i++)
  187.       aService.deleteItem(items[i].ID);
  188.       
  189.     //add the new items
  190.     for (var id in this._items)
  191.       aService.setItem(this._items[id]);
  192.       
  193.     //return success
  194.     setPref("migrated", "0.9.10"); 
  195.     return true;
  196.   },
  197.   
  198.   /**
  199.    * Import a profile document.
  200.    *
  201.    * @param   A parent window to use for the file picker.
  202.    * @return  False if import fails.  Use the lastError property
  203.    *          for more information on the failure.
  204.    */
  205.   importDOM: function MigratorService_importDOM(aParent)
  206.   {
  207.     //setup error variables
  208.     const PREFIX = "ff.migrator.import.";
  209.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  210.     var message = "";
  211.     
  212.     //get file to import from
  213.     var file = this._filePicker("import", aParent);
  214.     
  215.     //picker was canceled
  216.     if (!file) {
  217.       message = this.bundle.GetStringFromName(PREFIX + "cancel.message");
  218.       this._error.init(SEVERITY_WARNING, name, message);
  219.       return false;
  220.     }
  221.     
  222.     //return an error if the file doesn't exist
  223.     if (!file.exists()) {
  224.       message = this.bundle.GetStringFromName(PREFIX + "exist.message");
  225.       this._error.init(SEVERITY_ERROR, name, message);
  226.       return false;
  227.     }  
  228.     
  229.     //return an error if we don't have read permission
  230.     if (!file.isReadable()) {
  231.       message = this.bundle.formatStringFromName(PREFIX + "read.message",
  232.                                                  [file.path], 1);
  233.       this._error.init(SEVERITY_ERROR, name, message);
  234.       return false;
  235.     }
  236.     
  237.     //convert the file to a xml document
  238.     var doc = this._dskSvc.read(file);
  239.     
  240.     //return an error if it is not a valid xml document
  241.     if (!this._dskSvc.validate(doc, "forecastfox-settings")) {
  242.       message = this.bundle.GetStringFromName(PREFIX + "valid.message");
  243.       this._error.init(SEVERITY_ERROR, name, message);
  244.       return false;
  245.     }
  246.        
  247.     //return an error if no profiles in the document
  248.     var profiles = doc.getElementsByTagName("profile");
  249.     if (profiles.length == 0) {
  250.       message = this.bundle.GetStringFromName(PREFIX + "profiles.message");
  251.       this._error.init(SEVERITY_ERROR, name, message);
  252.       return false;
  253.     }
  254.  
  255.     //return an error if we could not get the version we are importing from
  256.     var version = getVersion(doc);
  257.     if (version == null) {
  258.       message = this.bundle.GetStringFromName(PREFIX + "version.message");
  259.       this._error.init(SEVERITY_ERROR, name, message);
  260.       return false;
  261.     }
  262.     
  263.     //get the profile service
  264.     var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
  265.                  getService(Ci.ffIManagerService);
  266.     var prfSvc = mgrSvc.profiles;
  267.     
  268.     //loop through the nodes and create profile items
  269.     this._items = {};
  270.     for (var i=0; i<profiles.length; i++) {
  271.       var item = prfSvc.createItem(profiles[i]);
  272.       this._items[item.ID] = item.clone();
  273.     }
  274.     
  275.     //run the upgrade if needed
  276.     var success = this._upgrade(version);
  277.     
  278.     //return an error if the upgrade failed
  279.     if (!success) {
  280.       this._error.init(this._error.severity, name, this._error.message);
  281.       return false;
  282.     }
  283.     
  284.     //start batch mode on the service
  285.     prfSvc.startBatch();
  286.     
  287.     //remove any old profiles
  288.     var items = prfSvc.getItems({});
  289.     for (i=0; i<items.length; i++)
  290.       prfSvc.deleteItem(items[i].ID);
  291.       
  292.     //add the new items
  293.     for (var id in this._items)
  294.       prfSvc.setItem(this._items[id]);
  295.       
  296.     //stop batch mode
  297.     prfSvc.endBatch(); 
  298.       
  299.     //return successful
  300.     return true;
  301.   },
  302.   
  303.   /**
  304.    * Export a profile document.
  305.    *
  306.    * @param   A parent window to use for the file picker.
  307.    * @return  False if export fails.  Use the lastError property
  308.    *          for more information on the failure.
  309.    */
  310.   exportDOM: function MigratorService_exportDOM(aParent)   
  311.   {
  312.     //setup error variables
  313.     const PREFIX = "ff.migrator.export.";
  314.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  315.     var message = "";
  316.     
  317.     //get file to export to
  318.     var file = this._filePicker("export", aParent);
  319.     
  320.     //picker was canceled
  321.     if (!file) {
  322.       message = this.bundle.GetStringFromName(PREFIX + "cancel.message");
  323.       this._error.init(SEVERITY_WARNING, name, message);
  324.       return false;
  325.     }
  326.     
  327.     //append ".xml" to the file if necessary
  328.     if (!file.leafName.match(/.xml$/))
  329.       file.leafName = file.leafName + ".xml";
  330.     
  331.     //return an error if we don't have write permission
  332.     if ((file.exists() && !file.isWritable()) ||
  333.         (!file.exists() && !file.parent.isWritable())) {
  334.       message = this.bundle.formatStringFromName(PREFIX + "write.message",
  335.                                                  [file.path], 1);
  336.       this._error.init(SEVERITY_ERROR, name, message);
  337.       return false;
  338.     }
  339.     
  340.     //create an export document
  341.     var doc = this._dskSvc.create("forecastfox-settings", PROFILES_DTD, 
  342.                                   PROFILES_NS);
  343.     
  344.     //get the profile service
  345.     var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
  346.                  getService(Ci.ffIManagerService);
  347.     var prfSvc = mgrSvc.profiles;
  348.     
  349.     //loop through the profiles and append nodes
  350.     var items = prfSvc.getItems({});
  351.     for (var i=0; i<items.length; i++) {
  352.       var node = prfSvc.createNode(items[i], doc);
  353.       doc.documentElement.appendChild(node);
  354.     }
  355.       
  356.     //write to disk
  357.     this._dskSvc.write(file, doc, false, true);
  358.       
  359.     //return successful
  360.     return true;
  361.   },
  362.          
  363.   ///////////////////////////
  364.   // Internal functions
  365.   
  366.   /**
  367.    * Upgrade profile items to the current version.
  368.    *
  369.    * @param   The original version of the profile items.
  370.    * @return  False if the upgrade fails.
  371.    */
  372.   _upgrade: function MigratorService__upgrade(aVersion)
  373.   {
  374.     // upgrade is not needed
  375.     if (this.compare(aVersion, "0.9.10") == 0)
  376.       return true;
  377.       
  378.     //setup error variables
  379.     const PREFIX = "ff.migrator.upgrade.";
  380.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  381.     var message = "";
  382.       
  383.     //get the upgrade file  
  384.     var file = this._dskSvc.get("upgrade.js", TYPE_DEFAULTS);
  385.  
  386.     //upgrade file does not exist
  387.     if (!file.exists()) {
  388.       message = this.bundle.GetStringFromName(PREFIX + "exists.message");
  389.       this._error.init(SEVERITY_ERROR, name, message);
  390.       return false;
  391.     }
  392.     
  393.     //upgrade file is not readable
  394.     if (!file.isReadable()) {
  395.       message = this.bundle.formatStringFromName(PREFIX + "read.message",
  396.                                                   [file.path], 1);
  397.       this._error.init(SEVERITY_ERROR, name, message);
  398.       return false;
  399.     }
  400.     
  401.     //read the file
  402.     var content = this._dskSvc.readText(file);
  403.     if (!content) {
  404.       message = this.bundle.GetStringFromName(PREFIX + "empty.message");
  405.       this._error.init(SEVERITY_ERROR, name, message);
  406.       return false;
  407.     }
  408.     
  409.     //get the upgrade actions
  410.     try {
  411.       var actions = eval(content);
  412.     } catch(e) {
  413.       this._error.init(SEVERITY_ERROR, e.name, e.message);
  414.       return false;  
  415.     }
  416.     
  417.     //loop until we hit the current version
  418.     var version = aVersion;
  419.     var comp = this;    
  420.     while (this.compare(version, "0.9.10") < 0) {
  421.     
  422.       //version does not exist in upgrade file
  423.       if (!actions.hasOwnProperty(version)) {
  424.         message = this.bundle.formatStringFromName(PREFIX + "version.message",
  425.                                                    [version], 1);
  426.         this._error.init(SEVERITY_ERROR, name, message);
  427.         return false; 
  428.       }
  429.       
  430.       //run the upgrade
  431.       try {
  432.         version = actions[version]();
  433.       } catch(e) {
  434.         message = this.bundle.formatStringFromName(PREFIX + "action.message",
  435.                                                    [version, e.message], 2);
  436.         this._error.init(SEVERITY_ERROR, name, message);
  437.         return false; 
  438.       }
  439.     }
  440.     
  441.     //upgrade was successful
  442.     return true;
  443.   },
  444.   
  445.   /**
  446.    * Show the file picker for import and export.
  447.    *
  448.    * @param   Mode for the file picker.
  449.    * @param   Parent window of the picker.
  450.    * @return  Null if picker canceled.  The nsIFile selected.
  451.    */
  452.   _filePicker: function MigratorService__filePicker(aMode, aParent)
  453.   {
  454.     //get the picker component
  455.     var picker = Cc["@mozilla.org/filepicker;1"].
  456.                  createInstance(Ci.nsIFilePicker);  
  457.     
  458.     //setup the pickers properties             
  459.     picker.appendFilters(Ci.nsIFilePicker.filterXML);
  460.     picker.defaultExtension = ".xml";
  461.     
  462.     //initialize the picker
  463.     var title = "ff.migrator.picker." + aMode;
  464.     title = this.bundle.GetStringFromName(title);
  465.     switch (aMode) {
  466.       case "export":
  467.         picker.init(aParent, title, picker.modeSave);
  468.         break;
  469.       case "import":
  470.         picker.init(aParent, title, picker.modeOpen);
  471.         break;
  472.     }
  473.     
  474.     //get the file and its contents
  475.     var res = picker.show();
  476.     if (res == picker.returnCanel)
  477.       return null;
  478.     else
  479.       return picker.file;  
  480.   },
  481.   
  482.   /**
  483.    * Load the profiles document.  First tries to load
  484.    * profiles.xml.  If that fails it tries profiles.bak.
  485.    * If that fails it creates a default document.
  486.    *
  487.    * @param   The profiles service.
  488.    * @return  The profiles dom.
  489.    */
  490.   _loadDoc: function MigratorService__loadDoc(aService)
  491.   {
  492.     //setup error variables
  493.     const PREFIX = "ff.migrator.migrate.";
  494.     var name = this.bundle.GetStringFromName(PREFIX + "name");
  495.     var message = "";  
  496.     var doc = null;
  497.     
  498.     //get profiles.xml
  499.     var file = this._dskSvc.get("profiles.xml", TYPE_PROFILE);
  500.     if (file.exists()) {
  501.     
  502.       //file not readable-writable
  503.       if (!file.isReadable() || !file.isWritable()) {
  504.         message = this.bundle.formatStringFromName(PREFIX + ".perms.message",
  505.                                                    [file.path], 1);
  506.         this._error.init(SEVERITY_ERROR, name, message);
  507.         return null;                                            
  508.       }
  509.       
  510.       //read the file into a document
  511.       doc = this._dskSvc.read(file);
  512.       
  513.       //doc is valid so return it
  514.       if (this._dskSvc.validate(doc, "profiles"))
  515.         return doc;
  516.       
  517.       //not valid log it  
  518.       else
  519.         this._dskSvc.log("profiles.xml is not a valid document.", null, file);      
  520.     
  521.     //profiles.xml does not exist
  522.     } else
  523.       this._dskSvc.log("Expected profiles.xml, but was missing.", null, null);
  524.       
  525.     //get profiles.bak
  526.     file = this._dskSvc.get("profiles.bak", TYPE_PROFILE);
  527.     
  528.     //backup exists and is readable
  529.     if (file.exists() && file.isReadable()) {    
  530.       doc = this._dskSvc.read(file);
  531.       
  532.       //doc is valid so return it
  533.       if (this._dskSvc.validate(doc, "profiles"))
  534.         return doc;
  535.       
  536.       //not valid log it  
  537.       else
  538.         this._dskSvc.log("profiles.bak is not a valid document.", null, file);
  539.          
  540.     //profiles.bak does not exist or is not readable
  541.     } else
  542.       this._dskSvc.log("Expected profiles.bak, but was missing.", null, null);
  543.       
  544.     //create an empty doc
  545.     doc = this._dskSvc.create("profiles", PROFILES_DTD, PROFILES_NS); 
  546.     
  547.     //append the current preference
  548.     var node = aService.createNode(aService.recreateItem(), doc);
  549.     doc.documentElement.appendChild(node);
  550.     
  551.     //return the document
  552.     return doc;        
  553.   }
  554. };